home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / utility / ini10.zip / CONFIG.C < prev    next >
Text File  |  1992-06-08  |  27KB  |  915 lines

  1.  
  2. /**
  3. * module    DBC\CONFIG
  4. *
  5. * purpose    Used to access "CONFIG.SYS-format" and "WIN.INI-format" files.
  6. *        Similar to Windows Initialization File functions.
  7. *        The following file format is processed:
  8. *
  9. *            ; comment
  10. *            [SectionName]    or  [SectionName] ; comment
  11. *            KeyName=string    or  KeyName=string ; comment
  12. *            KeyName=    or  KeyName= ; null string
  13. *                   =string    or       =string ; blank KeyName
  14. *            KeyName     or  KeyName ; same as KeyName=
  15. *
  16. *        Comments must be on separate lines or else the ';' must be
  17. *        preceded by a blank (to allow ';' to occur in strings).
  18. *        Blanks are not allowed between "SectionName" and the brackets.
  19. *        "SectionName" and "KeyName" are not case-dependent, so the
  20. *        strings may contain any combination of upper and lower case.
  21. *        If there is no equal sign, the entire line is assumed the key.
  22. *        The existence of an equal sign (after the removal of comments)
  23. *        determines that a string exists; otherwise it is assumed Null.
  24. *        Blanks around "KeyName" and "string" are ignored.  A null or
  25. *        blank KeyName (when an equal sign is present) is assumed to be
  26. *        a single blank.  Blank lines are allowed anywhere and ignored.
  27. *        SectionNames must be unique, since only the first one is used.
  28. *        KeyNames should be unique, since all are processed similarly.
  29. *
  30. * logic     The file is processed sequentially.  Each line is read, detabbed
  31. *        and parsed and then a "call-back" function is called with the
  32. *        resulting line components determined.  The components are:
  33. *
  34. *            FilePre         file line (including comments)
  35. *
  36. *        and (if available)
  37. *
  38. *            FileKey -> FilePost    left of the equal sign
  39. *                        (a blank if there is no key)
  40. *        and    FileString -> FilePost    right of the equal sign
  41. *                        (Null if there is no string)
  42. *
  43. *        The call-back function returns a code to indicate continued
  44. *        scanning.  The parser returns if either the end-of-file is
  45. *        reached or the call-back function ended the parsing.
  46. *
  47. * cautions    Argument checking is not performed.
  48. *
  49. * includes    <dbc/config.h>
  50. *
  51. * copyright    (c) Fran Finnegan Associates 1986, 1987
  52. * copyright    (c) 1988-92 Finnegan O'Malley & Company Inc.
  53. **/
  54.  
  55. #ifndef LINT_ARGS
  56. #define LINT_ARGS
  57. #endif
  58.     #include <io.h>
  59.     #include <malloc.h>
  60. //    #include <stdio.h>
  61.     #include <stdlib.h>
  62. //    #include <string.h>
  63.  
  64.     #include "ascii.i"
  65. //    #include "const.i"
  66.     #include "filespec.i"
  67. //    #include "string.i"
  68. //    #include "config.i"
  69.  
  70. #define NAME_SIZE    64    /* for FileNames, SectionNames and KeyNames */
  71. #define LINE_SIZE    256    /* for file lines */
  72.  
  73. #define ABOUT_TO_BEGIN    -1    /* to call-back:  about to begin reading file */
  74. #define NOT_IN_SECTION    NO    /* to call-back:  not in Section requested */
  75. #define ARE_IN_SECTION    YES    /* to call-back:  are in Section requested */
  76. #define END_OF_PROCESS    2    /* to call-back:  end-of-process was reached */
  77.  
  78. #define CONTINUE    1    /* to ParseFile:  continue reading file */
  79. #define STOP        2    /* to ParseFile:  stop reading file */
  80.  
  81. #define ACCESS_EXISTS    0    /* "access" existence-only mode */
  82. #define ACCESS_UNLINK    6    /* "access" read-and-write mode */
  83.  
  84.     int        gbConfigCloseFileOnExit = NO;
  85.     int        gbConfigDeleteBakOnExit = YES;                                        static char *_="\x20\x28\x63\x29 \x31\x39\x39\x32 \x46\x69\x6E\x6E\x65\x67\x61\x6E \x4F\x27\x4D\x61\x6C\x6C\x65\x79\x2E\x20";
  86.  
  87. static    int        mfnGetConfigString(int);
  88. static    int        mfnWriteConfigString(int);
  89. static    int        mfnGetConfigSection(int);
  90. static    int        mfnGetConfigKeys(int);
  91.  
  92. static    void        CloseFile(void);
  93. static    void        ParseFile(char *, char *, int (*)(int));
  94. static    void        ParseSection(char *, char *);
  95. static    void        ParseKey(char *, char *);
  96. static    char        *MemoryGetString(char *, int, char far **);
  97.  
  98. static    char        far *mlpmemConfig;    /* memory file in process */
  99. static    FILE        *mpfileConfig;        /* stream file in process */
  100. static    char        *mpszUserDefault;    /* user supplied */
  101. static    char        *mpszUserReturned;    /* user supplied */
  102. static    unsigned int      muiUserSize;        /* user supplied */
  103. static    char        *mpszUserString;    /* user supplied */
  104. static    char        *mpszFileKey;        /* pointer to mszFilePost */
  105. static    char        *mpszFileString;    /* pointer to mszFilePost */
  106. static    int           miReturn;        /* return code */
  107. static    int           mbWriteRequest;    /* WriteConfig... request */
  108. static    char    mszUserFile   [NAME_SIZE],    /* "d:\\path\\filename.ext" */
  109.         mszUserSection[NAME_SIZE],    /* "[SectionName]" or "" */
  110.         mszUserKey    [NAME_SIZE],    /* "KeyName" or " " */
  111.         mszFilePre    [LINE_SIZE],    /* pre-parsing line */
  112.         mszFilePost   [LINE_SIZE];    /* post-parsing line */
  113.  
  114. /*p*/
  115.  
  116. /**
  117. * function    GetConfigInt
  118. *
  119. * purpose    Similar to Windows "GetProfileInt".
  120. *
  121. * logic     Calls "GetConfigString".
  122. *
  123. * cautions    Unless the file contains a valid int, the default is returned.
  124. *
  125. * usage     iKeyValue = GetConfigInt(pszFilespec, pszSection, pszKey,
  126. *            iDefault);
  127. *
  128. * arguments    pszFilespec    "d:\\path\\filename.ext" format.
  129. *                pszFilespec must not be NULL.
  130. *        pszSection    "SectionName" of "[SectionName]".
  131. *                pszSection may be NULL, implying "".
  132. *        pszKey        "KeyName" of "KeyName=string".
  133. *                pszKey may be NULL, implying " ".
  134. *        iDefault    Default int if the SectionName/KeyName
  135. *                combination does not exist or is Null.
  136. *
  137. * returns    iKeyValue = int value of the key string.
  138. *
  139. * modifies    no externals.
  140. *
  141. * examples    iDOSbuffers = GetConfigInt("C:\\CONFIG.SYS", NULL, "buffers",
  142. *            -1);
  143. *
  144. * copyright    (c) Fran Finnegan Associates 1986, 1987
  145. **/
  146.  
  147. extern    int        GetMemoryInt(lpmemConfig, pszSection, pszKey, iDefault)
  148.  
  149.     char        far *lpmemConfig,
  150.             *pszSection,
  151.             *pszKey;
  152.     int        iDefault;
  153. {
  154. auto    int        iReturn;
  155.  
  156. CloseFile();
  157. mlpmemConfig = lpmemConfig;
  158. iReturn = GetConfigInt(NULL, pszSection, pszKey, iDefault);
  159. mlpmemConfig = (char far *)NULL;
  160. return (iReturn);
  161. }
  162.  
  163. extern    int        GetConfigInt(pszFilespec, pszSection, pszKey, iDefault)
  164.  
  165.     char        *pszFilespec,
  166.             *pszSection,
  167.             *pszKey;
  168.     int        iDefault;
  169. {
  170. auto    char        szReturned[12];     /* [12] should be sufficient */
  171.  
  172. return ((GetConfigString(pszFilespec, pszSection, pszKey, "", szReturned,
  173.         sizeof(szReturned)) and
  174.     strspn(szReturned, "+-0123456789"))?  atoi(szReturned):  iDefault);
  175. }
  176.  
  177. /*p*/
  178.  
  179. /**
  180. * function    GetConfigString
  181. *
  182. * purpose    Similar to Windows "GetProfileString".
  183. *
  184. * logic     See "arguments" below.
  185. *
  186. * cautions    The "Returned" buffer must be at least 2 bytes long.  It should
  187. *        be one byte longer than the longest expected "string".
  188. *
  189. * usage     iLength = GetConfigString(pszFilespec, pszSection, pszKey,
  190. *            pszDefault, pszReturned, uisize);
  191. *
  192. * arguments    pszFilespec    "d:\\path\\filename.ext" format.
  193. *                pszFilespec must not be NULL.
  194. *        pszSection    "SectionName" of "[SectionName]".
  195. *                pszSection may be NULL, implying "".
  196. *                Blanks around pszSection are ignored.
  197. *                Brackets are not included, but added herein.
  198. *                If pszSection == "":
  199. *                    SectionNames in the file are ignored.
  200. *        pszKey        "KeyName" of "KeyName=string".
  201. *                pszKey may be NULL, implying " ".
  202. *                Blanks around pszKey are ignored.
  203. *                If pszKey == "":
  204. *                    A null or blank KeyName is searched for.
  205. *        pszDefault    Default string if the SectionName/KeyName
  206. *                combination does not exist or is Null.
  207. *                If pszDefault == NULL:
  208. *                    The KeyName itself is the default.
  209. *                If pszDefault == "":
  210. *                    The Null string is the default.
  211. *                The default is used if either the KeyName does
  212. *                not exist or the Key string exists but is Null.
  213. *        pszReturned    Returned-string buffer (at least 2 bytes).
  214. *        uisize        Returned-string buffer size.
  215. *
  216. * returns    iLength = int length of returned string.  0 indicates Null ("").
  217. *
  218. * modifies    no externals.
  219. *
  220. * examples    auto    char    szDOSshell[64];
  221. *
  222. *        iDOSshell = GetConfigString("C:\\CONFIG.SYS", NULL, "shell",
  223. *            "C:\\COMMAND.COM", szDOSshell, sizeof(szDOSshell));
  224. *
  225. * copyright    (c) Fran Finnegan Associates 1986, 1987
  226. **/
  227.  
  228. extern    int        GetMemoryString(lpmemConfig, pszSection, pszKey,
  229.                 pszDefault, pszReturned, uisize)
  230.  
  231.     char        far *lpmemConfig,
  232.             *pszSection,
  233.             *pszKey,
  234.             *pszDefault,
  235.             *pszReturned;
  236.     unsigned int    uisize;
  237. {
  238. auto    int        iReturn;
  239.  
  240. CloseFile();
  241. mlpmemConfig = lpmemConfig;
  242. iReturn = GetConfigString(NULL, pszSection, pszKey, pszDefault, pszReturned,
  243.     uisize);
  244. mlpmemConfig = (char far *)NULL;
  245. return (iReturn);
  246. }
  247.  
  248. extern    int        GetConfigString(pszFilespec, pszSection, pszKey,
  249.                 pszDefault, pszReturned, uisize)
  250.  
  251.     char        *pszFilespec,
  252.             *pszSection,
  253.             *pszKey,
  254.             *pszDefault,
  255.             *pszReturned;
  256.     unsigned int    uisize;
  257. {
  258. ParseKey(mszUserKey, pszKey);                    /* Key        */
  259. mpszUserDefault = pszDefault;                    /* Default  */
  260. mpszUserReturned = pszReturned;                 /* Returned */
  261. muiUserSize = uisize;                        /* Size     */
  262. ParseFile(pszFilespec, pszSection, mfnGetConfigString);
  263. return (miReturn);
  264. }
  265.  
  266. /*p*/
  267.  
  268. static    int        mfnGetConfigString(iCase)
  269.  
  270.     int        iCase;
  271. {
  272. static    FILE        *pfileConfig;        /* stream file last processed */
  273. static    int        bInSection = NO,
  274.             bKeyFound = NO,
  275.             iFile_cnt = -1;
  276. static    char        szUserFile   [NAME_SIZE],
  277.             szUserSection[NAME_SIZE];
  278.  
  279. register char        *pC;
  280.  
  281. switch (iCase) {
  282.  
  283.     case ABOUT_TO_BEGIN:
  284.     bKeyFound = NO;
  285.     *mpszUserReturned = Null;
  286.     if (muiUserSize < 2)    /* buffer size must be at least 2 bytes */
  287.         return (STOP);
  288.     memset(mpszUserReturned, Null, muiUserSize--); /* -- insures a string */
  289.     if (bInSection and
  290.         pfileConfig and
  291.         pfileConfig == mpfileConfig and
  292.         iFile_cnt == mpfileConfig->_cnt and
  293.         no ferror(mpfileConfig) and
  294.         IsStrEquiv(szUserFile    , mszUserFile    ) and
  295.         IsStrEquiv(szUserSection, mszUserSection) and
  296.         fgets(mszFilePre, LINE_SIZE, mpfileConfig)) {    /* has '\n' */
  297.         StrTrunc(mszFilePre, " \t\r\n");
  298.     //  StrDetab(mszFilePre);
  299.         if (!IsStrNull(mszFilePre) and
  300.             *mszFilePre != ';') {
  301.         if (pC = strstr(mszFilePre, " ;"))
  302.             *pC = Null;             /* remove comments */
  303.         StrCrop(mszFilePre, " ");               /* now "Key = String" */
  304.         if (!IsStrNull(mszFilePre)) {          /* or "Key=" or "Key" */
  305.             if (pC = strchr(mszFilePre, '=')) { /* if an equal sign */
  306.             *pC++ = Null;            /* end Key */
  307.             pC = StrSkip(pC, " ");          /* skip to String */
  308.             StrTrunc(mszFilePre, " ");      /* truncate Key */
  309.             }
  310.             if (IsStrEquiv(mszFilePre, mszUserKey)) {
  311.             bKeyFound = YES;
  312.             if (pC)
  313.                 strncpy(mpszUserReturned, pC, muiUserSize);
  314.             mfnGetConfigString(END_OF_PROCESS);    /* recursion! */
  315.             if (gbConfigCloseFileOnExit)
  316.                 CloseFile();
  317.             return (STOP);
  318.             }
  319.             }
  320.         }
  321.         }
  322.     strcpy(szUserFile   , mszUserFile   );
  323.     strcpy(szUserSection, mszUserSection);
  324.     bInSection = NO;
  325.     break;
  326.  
  327.     case ARE_IN_SECTION:
  328.     bInSection = YES;
  329.     if (mpszFileKey and IsStrEquiv(mpszFileKey, mszUserKey)) {
  330.         bKeyFound = YES;
  331.         strncpy(mpszUserReturned, mpszFileString, muiUserSize);
  332.         if (IsStrNULL(mpszUserDefault))
  333.         mpszUserDefault = mpszFileKey;
  334.         return (STOP);    /* Key was found */
  335.         }
  336.     break;
  337.  
  338.     case NOT_IN_SECTION:
  339.     if (bInSection) {
  340.         bInSection = NO;
  341.         return (STOP);    /* was in, but am now not */
  342.         }
  343.     break;
  344.  
  345.     case END_OF_PROCESS:
  346.     if (bKeyFound)
  347.         while (!IsStrNull(mpszUserReturned)) {
  348.         pC = StrNull(mpszUserReturned) - 1;
  349.         if (*pC != '\\')
  350.             break;
  351.         *pC = '\0';
  352.         if (no fgets(mszFilePre, LINE_SIZE, mpfileConfig))
  353.             break;                    /* has '\n' */
  354.         StrTrunc(mszFilePre, " \t\r\n");
  355.         //    StrDetab(mszFilePre);
  356.         StrLeft(mszFilePre, " ");
  357.         strncpy(pC, mszFilePre, muiUserSize - strlen(mpszUserReturned));
  358.         }
  359.     if (IsStrNull(mpszUserReturned))
  360.         strncpy(mpszUserReturned, (mpszUserDefault?  mpszUserDefault:
  361.             mszUserKey), muiUserSize);
  362.     miReturn = strlen(mpszUserReturned);
  363.     iFile_cnt = (pfileConfig = mpfileConfig)?  mpfileConfig->_cnt:    -1;
  364.     break;         /* the '=' in the above line is OK */
  365.     }
  366. return (CONTINUE);
  367. }
  368.  
  369. /*p*/
  370.  
  371. /**
  372. * function    WriteConfigString
  373. *
  374. * purpose    Similar to Windows "WriteProfileString".
  375. *        Writes "KeyName=string" in the requested "SectionName"
  376. *        (replacing an existing KeyName if it already exists).
  377. *
  378. * logic     See "arguments" below.  The original file (if it exists) is
  379. *        renamed to "*.BAK" after the new file is written.
  380. *
  381. * cautions    none.
  382. *
  383. * usage     iSuccess = WriteConfigString(pszFilespec, pszSection, pszKey,
  384. *            pszString);
  385. *
  386. * arguments    pszFilespec    "d:\\path\\filename.ext" format.
  387. *                pszFilespec must not be NULL.
  388. *        pszSection    "SectionName" of "[SectionName]".
  389. *                pszSection may be NULL, implying "".
  390. *                Blanks around pszSection are ignored.
  391. *                Brackets are not included, but added herein.
  392. *                If pszSection == "":
  393. *                    SectionNames in the file are ignored.
  394. *        pszKey        "KeyName" of "KeyName=string".
  395. *                pszKey may be NULL, implying " ".
  396. *                Blanks around pszKey are ignored.
  397. *                If pszKey == "":
  398. *                    A blank KeyName is written.
  399. *        pszString    "string" of "KeyName=string".
  400. *                If pszString is NULL, the old "KeyName=string"
  401. *                is removed.  A Null ("") pszString is permitted.
  402. *
  403. * returns    iSuccess = TRUE if successful, FALSE if not.
  404. *
  405. * modifies    no externals.
  406. *
  407. * examples    iSuccess = WriteConfigString("C:\\CONFIG.SYS", NULL, "files",
  408. *            "32");
  409. *
  410. * copyright    (c) Fran Finnegan Associates 1986, 1987
  411. **/
  412.  
  413. extern    int        WriteConfigString(pszFilespec, pszSection, pszKey,
  414.                 pszString)
  415.  
  416.     char        *pszFilespec,
  417.             *pszSection,
  418.             *pszKey,
  419.             *pszString;
  420. {
  421. mbWriteRequest = YES;
  422. ParseKey(mszUserKey, pszKey);                    /* Key        */
  423. mpszUserString = pszString;                    /* String   */
  424. ParseFile(pszFilespec, pszSection, mfnWriteConfigString);
  425. mbWriteRequest = NO;
  426. return (miReturn);
  427. }
  428.  
  429. /*p*/
  430.  
  431. static    int        mfnWriteConfigString(iCase)
  432.  
  433.     int        iCase;
  434. {
  435. static    FILE        *pfileTMP;
  436. static    int        bWritten;
  437. static    char        *pszCrLf,
  438.             szCrLf[] = "\n",
  439.             szBAK[] = "BAK",
  440.             szTMP[] = "TMP",
  441.             szFILEformat[] = "%s\n";
  442.  
  443. auto    char        szFilespec[FILESPEC     ],
  444.             szDrive   [FILESPEC_DRIVE],
  445.             szPath      [FILESPEC_PATH ],
  446.             szName      [FILESPEC_NAME ],
  447.             szExt      [FILESPEC_EXT  ];
  448.  
  449. switch (iCase) {
  450.  
  451.     case ABOUT_TO_BEGIN:
  452.     miReturn = NO;        /* used as a Section indicator */
  453.     if (*mszUserFile == ' ')
  454.         return (STOP);    /* old Filespec can not be a blank (NULL) */
  455.     ParseFilespec(mszUserFile, szDrive, szPath, szName, szExt);
  456.     if (IsStrEquiv(szExt, szBAK) or IsStrEquiv(szExt, szTMP))
  457.         return (STOP);    /* old Filespec can not be *.BAK or *.TMP */
  458.     if (!access(mszUserFile, ACCESS_EXISTS)) {    /* if exist *.old */
  459.         MakeFilespec(szFilespec, szDrive, szPath, szName, szBAK);
  460.         if (!access(szFilespec, ACCESS_EXISTS))    /* if exist *.BAK */
  461.         if (access(szFilespec, ACCESS_UNLINK) or unlink(szFilespec))
  462.             return (STOP);        /* could not delete *.BAK */
  463.         }
  464.     MakeFilespec(szFilespec, szDrive, szPath, szName, szTMP);
  465.     if (!access(szFilespec, ACCESS_EXISTS) or    /* if exist *.TMP */
  466.         no (pfileTMP = fopen(szFilespec, "wt")))  /* no new *.TMP */
  467.         return (STOP);              /* could not open *.TMP */
  468.     pszCrLf = "";
  469.     bWritten = mpszUserString == NULL;  /* assume written for removal */
  470.     break;
  471.  
  472.     case ARE_IN_SECTION:
  473.     if (IsStrNull(mszFilePre))
  474.         break;
  475.     if (*mszFilePost == '[') {
  476.         fprintf(pfileTMP, pszCrLf);
  477.         pszCrLf = szCrLf;
  478.         }
  479.     miReturn = YES;     /* used as a Section indicator */
  480.     if (mpszFileKey and IsStrEquiv(mpszFileKey, mszUserKey)) { /* a match */
  481.         if (!IsStrNULL(mpszUserString)) {             /* replace */
  482.         strcpy(StrSkip(mszFilePre, " "),
  483.             &mszUserKey[*mszUserKey == ' ']);
  484.         strcat(mszFilePre, (*mszUserKey != ' ' and *mszFilePre == ' ')?
  485.             " = ":  "=");
  486.         strcat(mszFilePre, mpszUserString);
  487.         }
  488.         bWritten++;  /* may be written here (in Section) multiple times */
  489.         }
  490.     if (!(IsStrNULL(mpszUserString) and /* !(string NULL & it is a match) */
  491.         mpszFileKey and IsStrEquiv(mpszFileKey, mszUserKey)))
  492.         fprintf(pfileTMP, szFILEformat, /*StrEntab()*/ mszFilePre); /* old/new */
  493.     break;
  494.  
  495.     case NOT_IN_SECTION:
  496.     if (IsStrNull(mszFilePre))
  497.         break;
  498.     if (miReturn and    /* used as a Section indicator */
  499.         not bWritten) {                     /* append */
  500.         fprintf(pfileTMP, "%s=%s\n", &mszUserKey[*mszUserKey == ' '],
  501.             mpszUserString);                    /* add */
  502.         bWritten = YES;
  503.         }
  504.     if (*mszFilePost == '[') {
  505.         fprintf(pfileTMP, pszCrLf);
  506.         pszCrLf = szCrLf;
  507.         }
  508.     fprintf(pfileTMP, szFILEformat, /*StrEntab()*/ mszFilePre); /* old */
  509.     break;
  510.  
  511.     case END_OF_PROCESS:
  512.     if (no miReturn and    /* used as a Section indicator */
  513.         !IsStrNull(mszUserSection)) {  /* never NULL */
  514.         fprintf(pfileTMP, pszCrLf);
  515.         fprintf(pfileTMP, szFILEformat, mszUserSection);        /* add */
  516.         }
  517.     if (not bWritten) {
  518.         strcpy(mszFilePre, &mszUserKey[*mszUserKey == ' ']);
  519.         strcat(mszFilePre, "=");
  520.         strcat(mszFilePre, mpszUserString);
  521.         fprintf(pfileTMP, szFILEformat,
  522.             /*StrEntab()*/ mszFilePre);             /* add */
  523.         }
  524.     fprintf(pfileTMP, "%c", A_EOF);                             /* EOF */
  525.     fclose(pfileTMP);
  526.     ParseFilespec(mszUserFile, szDrive, szPath, szName, szExt);
  527.     MakeFilespec(szFilespec, szDrive, szPath, szName, szBAK);
  528.     rename(mszUserFile, szFilespec);    /* rename *.old *.BAK */
  529.     if (gbConfigDeleteBakOnExit)
  530.         unlink(szFilespec);
  531.     MakeFilespec(szFilespec, szDrive, szPath, szName, szTMP);
  532.     rename(szFilespec, mszUserFile);    /* rename *.TMP *.old */
  533.     miReturn = YES;             /* OK */
  534.     break;
  535.     }
  536. return (CONTINUE);
  537. }
  538.  
  539. /*p*/
  540.  
  541. /**
  542. * function    GetConfigSection
  543. *
  544. * purpose    Gets an entire Section.  Each line is placed in the "Returned"
  545. *        buffer and terminated with a CR/LF (to be compatible with the
  546. *        Windows "DrawText" function).  The buffer is Null-terminated.
  547. *
  548. * logic     See "arguments" below.
  549. *
  550. * cautions    The "Returned" buffer must be at least 2 bytes long.  It should
  551. *        be long enough to accomodate the longest expected Section.
  552. *
  553. * usage     iLines = GetConfigSection(pszFilespec, pszSection, pszReturned,
  554. *                  uiSize);
  555. *
  556. * arguments    pszFilespec    "d:\\path\\filename.ext" format.
  557. *                pszFilespec must not be NULL.
  558. *        pszSection    "SectionName" of "[SectionName]".
  559. *                pszSection must be supplied and not be NULL.
  560. *                Blanks around pszSection are ignored.
  561. *                Brackets are not included, but added herein.
  562. *        pszReturned    Returned-string buffer (at least 2 bytes).
  563. *        uiSize        Returned-string buffer size.
  564. *
  565. * returns    iLines = number of lines found.  0 indicates that the Section
  566. *                was not found or had no lines.
  567. *
  568. * modifies    no externals.
  569. *
  570. * examples    auto    char    szWinIniColors[512];
  571. *
  572. *        iWinIniColors = GetConfigSection("C:\\WIN\\SYS\\WIN.INI",
  573. *            "Colors", szWinIniColors, sizeof(szWinIniColors));
  574. *
  575. * copyright    (c) Fran Finnegan Associates 1986, 1987
  576. **/
  577.  
  578. extern    int        GetMemorySection(lpmemConfig, pszSection, pszReturned,
  579.                 uiSize)
  580.  
  581.     char        far *lpmemConfig,
  582.             *pszSection,
  583.             *pszReturned;
  584.     unsigned int    uiSize;
  585. {
  586. auto    int        iReturn;
  587.  
  588. CloseFile();
  589. mlpmemConfig = lpmemConfig;
  590. iReturn = GetConfigSection(NULL, pszSection, pszReturned, uiSize);
  591. mlpmemConfig = (char far *)NULL;
  592. return (iReturn);
  593. }
  594.  
  595. extern    int        GetConfigSection(pszFilespec, pszSection, pszReturned,
  596.                 uiSize)
  597.  
  598.     char        *pszFilespec,
  599.             *pszSection,
  600.             *pszReturned;
  601.     unsigned int    uiSize;
  602. {
  603. mpszUserReturned = pszReturned;                 /* Returned */
  604. muiUserSize = uiSize;                        /* Size     */
  605. ParseFile(pszFilespec, pszSection, mfnGetConfigSection);
  606. return (miReturn);
  607. }
  608.  
  609. /*p*/
  610.  
  611. static    int        mfnGetConfigSection(iCase)
  612.  
  613.     int        iCase;
  614. {
  615. register int        iLength;
  616.  
  617. auto    char        *pC;
  618.  
  619. switch (iCase) {
  620.  
  621.     case ABOUT_TO_BEGIN:
  622.     miReturn = 0;        /* used as a line counter */
  623.     *mpszUserReturned = Null;
  624.     if (muiUserSize < 2 or IsStrNull(mszUserSection))
  625.         return (STOP);
  626.     memset(mpszUserReturned, Null, muiUserSize--);
  627.     break;
  628.  
  629.     case ARE_IN_SECTION:
  630.     if (*mszFilePre != ';' and      /* ignore comment */
  631.         miReturn++) {    /* used as a line counter */
  632.         if (pC = strstr(mszFilePre, " ;")) {
  633.         *pC = Null;        /* remove comment */
  634.         StrTrunc(mszFilePre, " ");
  635.         }
  636.         iLength = strlen(strcat(mszFilePre, "\r\n"));
  637.         if (iLength > muiUserSize)
  638.         mszFilePre[iLength = muiUserSize] = Null;
  639.         strcpy(mpszUserReturned, mszFilePre);
  640.         mpszUserReturned += iLength;  /* effectively concats */
  641.         if ((muiUserSize -= iLength) == 0)
  642.         return (STOP);    /* no more room */
  643.         }
  644.     break;
  645.  
  646.     case NOT_IN_SECTION:
  647.     if (miReturn)        /* used as a line counter */
  648.         return (STOP);    /* was in, but am now not */
  649.     break;
  650.  
  651.     case END_OF_PROCESS:
  652.     if (miReturn)        /* was in */
  653.         miReturn--;     /* ignore "[Section]" line */
  654.     break;
  655.     }
  656. return (CONTINUE);
  657. }
  658.  
  659. /*p*/
  660.  
  661. /**
  662. * function    GetConfigKeys
  663. *
  664. * purpose    Gets a set of Keys.  Each key is placed in the "Returned"
  665. *        buffer and terminated with a CR/LF (to be compatible with the
  666. *        Windows "DrawText" function).  The buffer is Null-terminated.
  667. *
  668. * logic     See "arguments" below.
  669. *
  670. * cautions    The "Returned" buffer must be at least 2 bytes long.  It should
  671. *        be long enough to accomodate the longest expected set of Keys.
  672. *
  673. * usage     iKeys = GetConfigKeys(pszFilespec, pszSection, pszReturned,
  674. *            uiSize);
  675. *
  676. * arguments    pszFilespec    "d:\\path\\filename.ext" format.
  677. *                pszFilespec must not be NULL.
  678. *        pszSection    "SectionName" of "[SectionName]".
  679. *                pszSection may be NULL, implying "".
  680. *                Blanks around pszSection are ignored.
  681. *                Brackets are not included, but added herein.
  682. *        pszReturned    Returned-string buffer (at least 2 bytes).
  683. *        uiSize        Returned-string buffer size.
  684. *
  685. * returns    iKeys = number of keys found.  0 indicates that the Section
  686. *                was not found or no keys were found.
  687. *
  688. * modifies    no externals.
  689. *
  690. * examples    auto    char    szWinIniFonts[1 K];
  691. *
  692. *        iWinIniFonts = GetConfigKeys("C:\\WIN\\SYS\\WIN.INI",
  693. *            "Fonts", szWinIniFonts, sizeof(szWinIniFonts));
  694. *
  695. * copyright    (c) Fran Finnegan Associates 1986, 1987
  696. **/
  697.  
  698. extern    int        GetMemoryKeys(lpmemConfig, pszSection, pszReturned,
  699.                 uiSize)
  700.  
  701.     char        far *lpmemConfig,
  702.             *pszSection,
  703.             *pszReturned;
  704.     unsigned int    uiSize;
  705. {
  706. auto    int        iReturn;
  707.  
  708. CloseFile();
  709. mlpmemConfig = lpmemConfig;
  710. iReturn = GetConfigKeys(NULL, pszSection, pszReturned, uiSize);
  711. mlpmemConfig = (char far *)NULL;
  712. return (iReturn);
  713. }
  714.  
  715. extern    int        GetConfigKeys(pszFilespec, pszSection, pszReturned,
  716.                 uiSize)
  717.  
  718.     char        *pszFilespec,
  719.             *pszSection,
  720.             *pszReturned;
  721.     unsigned int    uiSize;
  722. {
  723. mpszUserReturned = pszReturned;                 /* Returned */
  724. muiUserSize = uiSize;                        /* Size     */
  725. ParseFile(pszFilespec, pszSection, mfnGetConfigKeys);
  726. return (miReturn);
  727. }
  728.  
  729. /*p*/
  730.  
  731. static    int        mfnGetConfigKeys(iCase)
  732.  
  733.     int        iCase;
  734. {
  735. register int        iLength;
  736.  
  737. switch (iCase) {
  738.  
  739.     case ABOUT_TO_BEGIN:
  740.     miReturn = 0;        /* used as a key counter */
  741.     *mpszUserReturned = Null;
  742.     if (muiUserSize < 2)
  743.         return (STOP);
  744.     memset(mpszUserReturned, Null, muiUserSize--);
  745.     break;
  746.  
  747.     case ARE_IN_SECTION:
  748.     if (mpszFileKey) {
  749.         miReturn++;     /* used as a key counter */
  750.         iLength = strlen(strcat(mpszFileKey, "\r\n"));      /* BEWARE! */
  751.         if (iLength > muiUserSize)
  752.         mpszFileKey[iLength = muiUserSize] = Null;
  753.         strcpy(mpszUserReturned, mpszFileKey);
  754.         mpszUserReturned += iLength;  /* effectively concats */
  755.         if ((muiUserSize -= iLength) == 0)
  756.         return (STOP);    /* no more room */
  757.         }
  758.     break;
  759.  
  760.     case NOT_IN_SECTION:
  761.     if (miReturn)        /* used as a key counter */
  762.         return (STOP);    /* was in, but am now not */
  763.     break;
  764.     }
  765. return (CONTINUE);
  766. }
  767.  
  768. /*p*/
  769.  
  770. static    void        CloseFile()
  771. {
  772. if (mpfileConfig) {
  773.     fclose(mpfileConfig);
  774.     mpfileConfig = NULL;
  775.     }
  776. }
  777.  
  778. /***/
  779.  
  780. static    void        ParseFile(pszFilespec, pszSection, pfnCallBack)
  781.  
  782.     char        *pszFilespec,
  783.             *pszSection;
  784.     int        (*pfnCallBack)(int);
  785. {
  786. static    char        szPreviousFile[FILESPEC];    /* previous request */
  787. static    char        szBlankKey[] = " \r\n";         /* used for blank key */
  788.  
  789. register int        bFileUserSection;
  790. register char        *pC;
  791.  
  792. ParseKey(mszUserFile, pszFilespec);                /* Filespec */
  793. ParseSection(mszUserSection, pszSection);            /* Section  */
  794. if ((*pfnCallBack)(ABOUT_TO_BEGIN) == CONTINUE) {
  795.     if (mpfileConfig
  796.     and IsStrEquiv(szPreviousFile, mszUserFile))
  797.     rewind(mpfileConfig);
  798.     else {
  799.     CloseFile();
  800.     if (no mlpmemConfig)
  801.         mpfileConfig = fopen(strcpy(szPreviousFile, mszUserFile), "rt");
  802.     }
  803.     if (mpfileConfig
  804.     or    mlpmemConfig) {
  805.     bFileUserSection = IsStrNull(mszUserSection);    /* in Section? */
  806.     while (mlpmemConfig?
  807.         MemoryGetString(mszFilePre, LINE_SIZE, &mlpmemConfig):
  808.         fgets(mszFilePre, LINE_SIZE, mpfileConfig)) {    /* has '\n' */
  809.         StrTrunc(mszFilePre, " \t\r\n");
  810.     //  StrDetab(mszFilePre);
  811.         mpszFileKey = mpszFileString = NULL;  /* assume no "Key = String" */
  812.         *mszFilePost = Null;
  813.         if (!IsStrNull(mszFilePre)
  814.         and *mszFilePre != ';') {
  815.         strcpy(mszFilePost, mszFilePre);
  816.         if (pC = strstr(mszFilePost, " ;"))
  817.             *pC = Null;     /* remove comments */
  818.         StrCrop(mszFilePost, " ");      /* now "Key = String" */
  819.         if (!IsStrNull(mszFilePost))
  820.             if (*mszFilePost == '[')    /* assume a "[SectionName]" */
  821.             bFileUserSection = IsStrNull(mszUserSection)?  YES:
  822.                 IsStrEquiv(mszUserSection, mszFilePost);
  823.             else {            /* assume a "Key = string" */
  824.             if (pC = strchr(mszFilePost, '=')) {
  825.                 *pC++ = Null;
  826.                 mpszFileString = StrSkip(pC, " ");
  827.                 StrTrunc(mszFilePost, " ");
  828.                 }
  829.             else
  830.                 mpszFileString = "";  /* BEWARE OF STRCATTING! */
  831.             mpszFileKey = !IsStrNull(mszFilePost)?    mszFilePost:
  832.                 szBlankKey;      /* BEWARE OF STRCATTING! */
  833.             szBlankKey[1] = Null;    /* to allow for strcatting */
  834.             }
  835.         }
  836.         if ((*pfnCallBack)(bFileUserSection) == STOP)  /* do call-back */
  837.         break;
  838.         }
  839.     }
  840.     (*pfnCallBack)(END_OF_PROCESS);    /* file may not have been read */
  841.     if (mbWriteRequest or gbConfigCloseFileOnExit)
  842.     CloseFile();
  843.     }
  844. }
  845.  
  846. /*p*/
  847.  
  848. static    void        ParseSection(pszTo, pszFrom)
  849.  
  850.     char        *pszTo,
  851.             *pszFrom;
  852. {
  853. *pszTo++ = '[';                 /* add '[' */
  854. if (pszFrom) {
  855.     strncpy(pszTo, StrSkip(pszFrom, " "), NAME_SIZE - 3);
  856.     StrTrunc(pszTo, " ");
  857.     }
  858. else
  859.     *pszTo = Null;
  860. if (IsStrNull(pszTo))        /* if pszTo == "[]", */
  861.     *--pszTo = Null;        /*    SectionNames are to be ignored */
  862. else
  863.     strcat(pszTo, "]");         /* add ']' */
  864. }
  865.  
  866. /***/
  867.  
  868. static    void        ParseKey(pszTo, pszFrom)
  869.  
  870.     char        *pszTo,
  871.             *pszFrom;
  872. {
  873. if (pszFrom) {
  874.     strncpy(pszTo, StrSkip(pszFrom, " "), NAME_SIZE - 1);
  875.     StrTrunc(pszTo, " ");
  876.     }
  877. else
  878.     *pszTo = Null;
  879. if (IsStrNull(pszTo)) {     /* if pszTo == "", */
  880.     *pszTo++ = ' ';             /*      KeyNames must be at least " " */
  881.     *pszTo = Null;
  882.     }
  883. }
  884.  
  885. /***/
  886.  
  887. static    char        *MemoryGetString(pszBuffer, iN, plpmemMemory)
  888.  
  889.     char        *pszBuffer;
  890. register int        iN;
  891.     char        far **plpmemMemory;
  892. {
  893. register char        cChar;
  894.  
  895. auto    char        *pszString;
  896.  
  897. if (    **plpmemMemory == A_EOF or
  898.     **plpmemMemory == Null    /* or
  899.     no iN */  )
  900.     return (NULL);
  901. pszString = pszBuffer;
  902. pszString[--iN] = Null;
  903. while (iN--) {
  904.     while ((cChar = **plpmemMemory) == '\r')
  905.     ++*plpmemMemory;
  906.     if ((*pszString = cChar) == '\n')
  907.     *++pszString = Null;
  908.     if (cChar)
  909.     ++*plpmemMemory;
  910.     if (no *pszString++)
  911.     break;
  912.     }
  913. return (pszBuffer);
  914. }
  915.